/**************************************************************
  > File Name: 令牌桶.c
  > Author: LuoLiang
  > Mail: 1204553475@qq.com 
  > Created Time: 2022年01月30日 星期日 13时32分04秒
 **************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>

#define CPS 10
#define BUFSIZE CPS
#define BURST 100

volatile int token = 0;

void alrmAction(int s, siginfo_t *info, void *unuse)
{
	if (info->si_code != SI_KERNEL)
		return ;

	token++;
	if (token > BURST)
	{
		token = BURST;
	}
}

int main(int argc,char **argv)
{
	int fd;
	if (argc < 2)
	{
		fprintf(stderr,"Usage:\n");
		exit(1);
	}
	
	do
	{	
		fd = open(argv[1],O_RDONLY);
		if (fd < 0)
		{
			if (errno != EINTR)
			{
				perror("open()");
				exit(1);
			}
		}
	}while (fd < 0);

	size_t len = 0;
	size_t pos = 0;
	size_t ret = 0;
	char buf[BUFSIZE];
	struct itimerval itv;
	itv.it_interval.tv_sec = 1;
	itv.it_interval.tv_usec = 0;
	itv.it_value.tv_sec = 1;
	itv.it_value.tv_usec = 0;

	struct sigaction act;
	act.sa_sigaction = alrmAction;
	sigemptyset(&act.sa_mask);
	act.sa_flags = SA_SIGINFO;

	sigaction(SIGALRM, &act, NULL);
	setitimer(ITIMER_REAL, &itv, NULL);
	while (1)
	{
		while (token <= 0)
			pause();

		token--;
		while ((len = read(fd, buf, BUFSIZE)) < 0)
		{
			if (errno == EINTR)
				continue;
			perror("read()");
			break;
		}

		if (len == 0)
			break;

		pos = 0;
		while (len > 0)
		{
			ret = write(1, buf + pos, len);
			if (ret < 0)
			{
				perror("write()");
				exit(1);
			}
			pos += ret;
			len -= ret;
		}

		struct timespec ts;
		ts.tv_sec = 1;
		ts.tv_nsec = 0;
		nanosleep(&ts, NULL);
	}

	close(fd);
    exit(0);
}
